/*
 * Representacion.java
 * Copyright 2010 Universidad Francisco de Paula Santander (UFPS).
 * Todos los Derechos Reservados.
 * Creado el 21/04/2010, 11:15:16 AM
 */

package com.ufps.cuatro.util;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.StringTokenizer;

import com.ufps.cuatro.modelo.analizador.ObjetoReflexion;
import com.ufps.cuatro.modelo.analizador.UtilAnalizador;
import com.ufps.cuatro.modelo.representacion.CasoRepresentacion;
import com.ufps.cuatro.modelo.representacion.CasoRepresentacionInterno;
import com.ufps.cuatro.util.base.ModeloRepresentacionBase;
import com.ufps.cuatro.util.base.TipoDatoRepresentacionBase;
import com.ufps.cuatro.util.generadores.GeneradorComponentes;
import com.ufps.cuatro.util.opciones.MyProperties;

/**
 * <i><b>Representacion:</b></i>Esta Clase encapsula toda la configuración almacenada
 * en archivos properties para la configuración de la herramienta y de los procesos
 * para la construcción de las interfaces gráficas de los los modelos analizados.
 *
 * @author Carlos A. Torres C. - Dolly E. Guerrero. <https://code.google.com/p/tesis4dor/>
 * @version 1.0 21/04/2010
 *   
 */
public abstract class Representacion {    
    
    /**
     * Objeto que encapsula las opciones de Representación de Componentes Swing,
     * previamente almacenadas en el archivo de propiedades.
     */
    public static MyProperties objPropiedadesRepresentacion;
    /**
     * Objeto que encapsula los Oyentes configurados,
     * previamente almacenadas en el archivo de propiedades.
     */
    public static MyProperties objPropiedadesOyentes;
    /**
     * Objeto que encapsula los Casos configurados,
     * previamente almacenadas en el archivo de propiedades.
     */
    public static MyProperties objPropiedadesCasos;
    /**
     * Objeto que encapsula las Propiedades disponibles para los Componentes.
     * previamente almacenadas en el archivo de propiedades.
     */
    public static MyProperties objPropiedadesComponentes;        
    /**
     * Objeto que encapsula las Propiedades disponibles para los Patrones de Representaciones.
     * previamente almacenadas en el archivo de propiedades.
     */
    public static MyProperties objPropiedadesPatrones;                     
    /**
     * Objeto que encapsula las Propiedades disponibles para los Modelos.
     * previamente almacenadas en el archivo de propiedades.
     */
    public static MyProperties objPropiedadesModelos;                     

    static{
        init();          
    }           
    
    private static void init() {
        try{
        String strPath = Utileria.resourceMap.getResourcesDir() + Utileria.leerRecursoTexto("Utileria.properties.representacion");
        objPropiedadesRepresentacion = Utileria.cargar(strPath);        
        strPath = Utileria.resourceMap.getResourcesDir() + Utileria.leerRecursoTexto("Utileria.properties.oyentes");
        objPropiedadesOyentes = Utileria.cargar(strPath);
        strPath = Utileria.resourceMap.getResourcesDir() + Utileria.leerRecursoTexto("Utileria.properties.casos");
        objPropiedadesCasos = Utileria.cargar(strPath);
        strPath = Utileria.resourceMap.getResourcesDir() + Utileria.leerRecursoTexto("Utileria.properties.propiedades");
        objPropiedadesComponentes = Utileria.cargar(strPath);        
        strPath = Utileria.resourceMap.getResourcesDir() + Utileria.leerRecursoTexto("Utileria.properties.patrones");
        objPropiedadesPatrones = Utileria.cargar(strPath);          
        strPath = Utileria.resourceMap.getResourcesDir() + Utileria.leerRecursoTexto("Utileria.properties.modelos");
        objPropiedadesModelos = Utileria.cargar(strPath);       
        strPath = Utileria.resourceMap.getResourcesDir() + Utileria.leerRecursoTexto("Utileria.properties.modelos");
        objPropiedadesModelos = Utileria.cargar(strPath);
    }catch(java.lang.NullPointerException ex){}
        
    }

    /**
     * Analiza el CasoRepresentacion para un objeto class este caso es considerado especial,
     * ya que gneralmente depende de otro caso previamente generado.
     * @param objClass
     * @return un objeto caso simple ó especial.
     */
    public static CasoRepresentacionInterno crearCasoInterno(Class<?> objClass){
        try{
            if(objClass == null)return null;
            CasoRepresentacion objTempCaso = crearCaso(objClass);
            CasoRepresentacionInterno objCaso = new CasoRepresentacionInterno(objTempCaso);
            objCaso.setObjClass(objClass);
            return objCaso;
        }catch(java.lang.NullPointerException ex){}
        return null;
    }   

    /**
     * Método Generico que genera un caso general para un objeto Class.
     * @param objClass
     * @return el objeto caso generico utilizado como base para los otros casos.
     */
    @SuppressWarnings("unchecked")
    public static CasoRepresentacion crearCaso(Class<?> objClass){
       try{
            CasoRepresentacion objCaso = new CasoRepresentacion();
            objCaso.setObjClass(objClass);
            if(objClass.isArray()){
                objCaso.setObjClassInterna(objClass.getComponentType());
                objCaso.seteCaso(TipoCaso.eArray);
                objCaso.setArray(true);
                if(objClass.isEnum()){
                    objCaso.setEnumeracion(true);                                
                }
                else{                
                    //se obtiene el tipo de dato individual del array                
                    objCaso.setObjCasoInterno(Representacion.crearCasoInterno(objClass.getComponentType()));
                }
            }
            else if(objClass.isEnum()){
                objCaso.setEnumeracion(true);
                objCaso.seteCaso(TipoCaso.eEnumeracion);            
            }
            else{
                objCaso.seteCaso(Representacion.esCaso(objClass));
            }
            return objCaso;
        }catch(java.lang.NullPointerException ex){}
       return null;
    }         

    /**
     * Determina si el Objeto Method es un Método Set.
     * Se les llama por conveniencia a los métodos tipo void que reciben
     * un tipo de dato.
     * @param objMetodo
     * @return un booleano que determina el análisis del parametro.
     */
    public static boolean esCasoSet(Method objMetodo){
        try{
            if(objMetodo.getReturnType().getName().equals("void") &&
                    objMetodo.getParameterTypes().length == 1){
                //se determina que el metodo en cuestion es un
                //metodo set se debe establecer el caso para su parametro
                return true;
            }
            }catch(java.lang.NullPointerException ex){}
            return false;
        
    }

    /**
     * Determina si el Objeto Method es un Método Get.
     * Se les llama por conveniencia a los métodos que devuelven valores
     * y no recibe parametros.
     * @param objMetodo @DefinicionParametro
     * @return un booleano que determina el análisis del parametro.
     */
    public static boolean esCasoGet(Method objMetodo){
       try{
        if(!objMetodo.getReturnType().getName().equals("void") &&
                objMetodo.getParameterTypes().length == 0){
            //se determinaque el metodo en cuestion es un
            //metodo get se debe establecer el caso para su valor de retorno
            return true;
        }
        }catch(java.lang.NullPointerException ex){}
        return false;
    
       
    }
    
    /**
     * Determina el caso en el cual se puede representar el Parametro.
     * En la Implementación se han definido por Conveniencia 5 Casos Básicos en
     * los cuales se puede representar un Objeto analizado por reflexión, estos
     * casos determina el proceso a seguir para la generación de los componetnes que
     * representen el area de interfaz gráfica requerida.
     *
     * Los casos que pueden representar los objetos analizados se describen a continuación:
     * <li>
     * <ul>Primitivo:</ul><ol>Este CasoRepresentacion se utiliza para representar los tipos
     * de datos básicos del lenguaje, es decir, los tipos que no requieren instnaciación
     * en tiempo de ejecución por ejemplo: int, char, float, double, long.....
     * Estos caso por lo general no necesitan un compoente complejo ya que
     * generalmente su vista es simple.</ol>
     * </li>
     * <li>
     * <ul>JDKRegistrado:</ul><ol>Este CasoRepresentacion se utiliza para representar los tipos
     * de objetos de uso comun, es decir aquellos que pueden relacionarse con
     * compoentes por defecto, por ejemplo los tipos String usan etiquetas o
     * cajas de texto.</ol>
     * </li>
     * <li>
     * <ul>ClaseMundo:</ul><ol>Este CasoRepresentacion es la base de todos los casos analizados.
     * Teniendo en cuenta que el analisis se basa en el patron MVC una o varias clases 
     * serán controladoras y otras colaboradoras. Este caso es un poco complejo ya 
     * por lo general genera otros analisis creando ciertos bucles de configuración
     * antes de concluir con el caso inicial.
     * </ol>
     * </li>     
     * <li>
     * <ul>JDKNoRegistrado:</ul><ol>Este CasoRepresentacion es para aquellos objetos que pertenecen
     * al JDK pero no son comunes en su utilización este caso se analiza de manera similar
     * al CasoRepresentacion ClaseMundo.
     * </ol>
     * </li>
     * @param objClase
     * @return El tipo de caso que representa el Objeto Class.
     */
    public static TipoCaso esCaso(Class<?> objClase){
       try{
            if(objClase.isPrimitive()){//es un tipo primitivo
                return TipoCaso.ePrimitivo;
            }
            else if(objClase.isEnum()){//es un tipo primitivo
                return TipoCaso.eEnumeracion;
            }        
            else if(Representacion.esCasoRegistrado(objClase)){//es un tipo registrado
                return TipoCaso.eJDKRegistrado;
            }
            else if(Representacion.esCasoClaseMundo(objClase.getCanonicalName())){//es un tipo del mundo
                return TipoCaso.eClaseMundo;
            }
            else if(objClase.isArray()){//es un tipo primitivo
                return TipoCaso.eArray;
            }
            else {//es un tipo no registrado
                return TipoCaso.eJDKNoRegistrado;
            }
        }catch(java.lang.NullPointerException ex){}
       return null;
    }

    /**
     * Realiza el mismo analisis que el método esCaso pero para array.
     * @param objClase @DefinicionParametro
     * @return El tipo de caso que representa el Objeto Class.
     */
    public static TipoCaso esCasoArray(Class<?> objClase){
       try{
            if(objClase.isArray()){
                Class<?> objTempClase = objClase.getComponentType();
                if(objTempClase.isPrimitive()){//es un tipo primitivo
                    return TipoCaso.eArray;
                }
                else if(Representacion.esCasoRegistrado(objTempClase)){//es un tipo registrado
                    return TipoCaso.eArray;
                }
                else if(Representacion.esCasoClaseMundo(objTempClase.getCanonicalName())){//es un tipo del mundo
                    return TipoCaso.eArray;
                }            
                else {//es un tipo no registrado
                    return TipoCaso.eArray;
                }
            }
            return TipoCaso.eIndefinido;
        }catch(java.lang.NullPointerException ex){}
    return null;
    }

    /**
     * Determina si el parametro tiene un modelo asociado para su representación
     * por defecto, estos son lo posibles casos JDKRegistrado y el modelo ó
     * componente que lo representa debe estar deinido en un archivo de propiedades
     * previamente configurado.
     * @param objType @DefinicionParametro
     * @return un booleano que determina si el objeto es un JDKRegistrado.
     */
    public static boolean esCasoRegistrado(Class<?> objType){
       try{
        for(TipoDatoRepresentacionBase objTDRB : GeneradorComponentes.objTiposDatoRepresentacionBase){
            String strClassPath = objTDRB.getStrClassPath();
            if(strClassPath.equals(objType.getCanonicalName()) && !objTDRB.isPrimitive()){
                return true;                
            }
        }
        }catch(java.lang.NullPointerException ex){}
        return false;
    }   
    
    /**
     * @DefinicionMetodo
     * @param type @DefinicionParametro
     * @param modo @DefinicionParametro
     * @return @DefinicionReturn
     */
    public static ArrayList<ItemViewContenedor> getComponentesModeloRegistrado(String type, int modo){
       try{
        try{
            ArrayList<ItemViewContenedor> objControles = new ArrayList<ItemViewContenedor>();
            for(TipoDatoRepresentacionBase objTipoDato : GeneradorComponentes.objTiposDatoRepresentacionBase){
                if(objTipoDato.getStrClassPath().equals(type)){
                    ModeloRepresentacionBase objModeloBase = objTipoDato.getObjModeloBase();
                    StringTokenizer objTokens = 
                            new StringTokenizer((modo == Utileria.SET) ? 
                            objModeloBase.getStrComponentesGet() : 
                            objModeloBase.getStrComponentesSet()," ,");                       
                    while (objTokens.hasMoreTokens()) {
                        String valueToken = objTokens.nextToken();
                        String keyAlias = "Utileria.swing.control[" + valueToken + "].alias";
                        String keyClassPath = "Utileria.swing.control[" + valueToken + "].classpath";
                        String valueAlias = objPropiedadesRepresentacion.getProperty(keyAlias);
                        String valueClassPath = objPropiedadesRepresentacion.getProperty(keyClassPath);
                        ItemViewContenedor objItemCombo = new ItemViewContenedor(valueAlias, valueClassPath);
                        objControles.add(objItemCombo);
                    }
                }
            }
            return objControles;
        }catch(java.lang.NullPointerException ex){
            
        }
        return new ArrayList<ItemViewContenedor>();
    } catch(java.lang.NullPointerException ex){}
       return null;
    }  

    /**
     * Determina si el ClassPath pertenece a una de las Clase analizadas en el
     * modelo actual.
     * @param strCanonicalName @DefinicionParametro
     * @return el estado del analisis. 
     */
    public static boolean esCasoClaseMundo(String strCanonicalName){
       try{
        for(int i = 0; i < UtilAnalizador.objClases.size(); i++){
            ObjetoReflexion objTemp = UtilAnalizador.objClases.get(i);
            if(objTemp.getObj() != null){
                if(objTemp.getObj().getClass().getCanonicalName().equals(strCanonicalName)) {
                    return true;
                }
            }
            else if(objTemp.getObjClass() != null){
                if(objTemp.getObjClass().getCanonicalName().equals(strCanonicalName)) {
                    return true;
                }
            }
        }
        }catch(java.lang.NullPointerException ex){}
        return false;
    }

    /**
     * @DefinicionMetodo
     * @param objClase @DefinicionParametro
     * @param strPackage  @DefinicionParametro
     * @return @DefinicionReturn
     */
    public static boolean pertenecePaquete(Class<?> objClase, String strPackage){        
       try{
        if(objClase.getCanonicalName().startsWith(strPackage)) {
            return false;
        }
        }catch(java.lang.NullPointerException ex){}
        return true;
    }
    
    public static boolean isCollection(Class objClase){
//        String strPackage = Representacion.objPropiedadesRepresentacion.getProperty("Utileria.java.exception.package");
//        if(objClase.getCanonicalName().startsWith(strPackage))
//            return false;
//        String strCanonicalName = objClase.getCanonicalName();
//        String strClase = strCanonicalName;
//        String strSuper = Representacion.objPropiedadesRepresentacion.getProperty("Utileria.java.collection");
//        while(!strClase.equals(Object.class.getCanonicalName())){
//             if(Utileria.esPosibleInstanciar(strClase)){
//                 Object objNew = Utileria.crearInstancia(strClase);
//                 strClase = objNew.getClass().getSuperclass().getCanonicalName();
//                 if(strSuper.equals(strClase))
//                     return true;
//             }
//             else
//                 return false;
//        }
        return false;
    }

    
}

